﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using System.Reflection;
using System.Collections;
using System.Web.UI;
using System.Web;
using System.Globalization;

namespace UserLimitedGroupSelection.Code
{
    public class UserLimitedGroupSelectionEditor : PeopleEditor
    {
        /// <summary>
        /// AD account columns mapping
        /// </summary>
        internal struct PeopleInfo
        {
            public static readonly string AccountName = "AccountName";
            public static readonly string DisplayName = "DisplayName";
            public static readonly string JobTitle = "Title";
            public static readonly string Department = "Department";
            public static readonly string Email = "Email";
            public static readonly string SPUserId = "SPUserID";
            public static readonly string SPGroupId = "SPGroupID";
            public static readonly string SIPAddress = "SIPAddress";
            public static readonly string PrincipalType = "PrincipalType";
            public static readonly string MobilePhone = "MobilePhone";
            public static readonly string WorkPhone = "WorkPhone";
            public static readonly string Location = "Location";
        }

        /// <summary>
        /// Raises an event when the server control is initialized.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs" /> object that contains the event data.</param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            PickerDialogType = typeof(UserLimitedGroupSelectionDialog);
        }

        /// <summary>
        /// Creates the child controls.
        /// </summary>
        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            SPField currentField = GetCurrentField(this);

            //Set extra custom properties (these will be passed to the dialog through the url, to identify the current field)
            if (SPContext.Current.List != null &&
                currentField != null &&
                CustomProperty.Split(new char[] { ';' }).Length == 6)
                CustomProperty = String.Concat(CustomProperty, ";", SPContext.Current.List.ID, ";", currentField.Id);
        }

        /// <summary>
        /// Validates the specified entity.
        /// </summary>
        /// <param name="entity">A <see cref="T:Microsoft.SharePoint.WebControls.PickerEntity" /> object.</param>
        /// <returns></returns>
        public override PickerEntity ValidateEntity(PickerEntity entity)
        {
            //Validate entity coming from picker dialog
            //Logic copied from PeopleEditor
            PickerEntity[] array = null;
            SPPrincipalType sPPrincipalType = (SPPrincipalType)typeof(PeopleEditor).GetMethod("ConvertAccountSelectionToPrincipalTypes", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { (bool[])typeof(PeopleEditor).GetField("AccountSelection", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this) });
            PickerEntity resolvedEntity = UserLimitedGroupSelectionQuery.ResolveAD(entity.Key, GetCurrentField(this));

            if (resolvedEntity != null)
            {
                //Entity has 1 match
                entity = resolvedEntity;
                entity.IsResolved = true;

                array = new PickerEntity[]
                {
                    entity
                };
            }
            else
            {
                //Try to resolve the entity from the email address
                if ((sPPrincipalType & SPPrincipalType.User) == SPPrincipalType.User && this.AcceptAnyEmailAddresses && !string.IsNullOrEmpty(entity.Key))
                {
                    PickerEntity pickerEntity = (PickerEntity)typeof(PeopleEditor).GetMethod("EntityTryEmailAddress", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { entity });

                    if (pickerEntity != null)
                    {
                        pickerEntity.IsResolved = true;
                        
                        array = new PickerEntity[]
                        {
                            pickerEntity
                        };
                    }
                }

                if (array == null)
                {
                    //Perform search when enity was not resolved before
                    typeof(PeopleEditor).GetField("ExactMatch", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(this, false);

                    IList<PickerEntity> list = UserLimitedGroupSelectionQuery.SearchAD(entity.Key, 10, GetCurrentField(this));

                    foreach(PickerEntity pe in list)
                        pe.IsResolved = true;

                    array = list.ToArray();
                }
            }

            if (array == null || (array != null && array.Length == 0))
            {
                entity.Description = SPResource.GetString("PeoplePickerEntryNotFound", new object[0]);
                entity.IsResolved = false;
            }
            else
            {
                if (array.Length == 1 && (bool)typeof(PeopleEditor).GetField("ExactMatch", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this))
                    entity = array[0];
                else
                {
                    Hashtable moreMatches = (Hashtable)typeof(PeopleEditor).GetField("m_htMoreMatches", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this);
                    moreMatches[entity.Key] = array;

                    if (base.IsIE55Plus())
                        entity.Description = SPResource.GetString("PeoplePickerMoreResultsReturned", new object[0]);
                    else
                        entity.Description = SPResource.GetString("PeoplePickerMoreResultsReturnedDownLevel", new object[0]);
                }
            }

            typeof(PeopleEditor).GetField("ExactMatch", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(this, true);

            return entity;
        }

        /// <summary>
        /// Searches for matching picker entities by using the specified unresolved text.
        /// </summary>
        /// <param name="unresolvedText">A string that represents the unresolved text.</param>
        /// <returns></returns>
        protected override PickerEntity[] ResolveErrorBySearch(string unresolvedText)
        {
            //Validate string coming from user input
            return UserLimitedGroupSelectionQuery.SearchAD(unresolvedText, 10, GetCurrentField(this)).ToArray();
        }

        /// <summary>
        /// Gets the current field.
        /// </summary>
        /// <returns></returns>
        internal static UserLimitedGroupSelection GetCurrentField(UserLimitedGroupSelectionEditor editorControl)
        {
            //Field property is available when calling from PeopleEditor
            Control parentControl = editorControl.Parent;

            while (parentControl != null)
            {
                if (parentControl.GetType() == typeof(UserLimitedGroupSelectionControl))
                    return (UserLimitedGroupSelection)((UserLimitedGroupSelectionControl)parentControl).Field;

                parentControl = parentControl.Parent;
            }

            //Get field from query string params when calling form Dialog
            if(HttpContext.Current.Request.QueryString["CustomProperty"] != null)
            {
                string[] customProperties = HttpContext.Current.Request.QueryString["CustomProperty"].Split(new char[] { ';' });

                if (customProperties.Length == 8)
                {
                    SPList list = null;

                    try
                    {
                        list = SPContext.Current.Web.Lists[new Guid(customProperties[6])];
                    }
                    catch
                    {

                    }

                    if (list != null)
                    {
                        SPField field = null;

                        try
                        {
                            field = list.Fields[new Guid(customProperties[7])];
                        }
                        catch
                        {

                        }

                        if(field.GetType() == typeof(UserLimitedGroupSelection))
                            return (UserLimitedGroupSelection)field;
                    }
                }
            }

            return null;
        }

        /// <summary>
        /// Converts the principal info to picker entity.
        /// </summary>
        /// <param name="principal">The principal.</param>
        /// <returns></returns>
        internal static PickerEntity ConvertPrincipalInfoToPickerEntity(SPPrincipalInfo principal)
        {
            //Convert AD entry to PickerEntity
            //Logic copied from PeopleEditor
            PickerEntity pickerEntity = new PickerEntity();

            pickerEntity.Key = principal.LoginName;
            pickerEntity.DisplayText = principal.DisplayName;

            if (string.IsNullOrEmpty(pickerEntity.DisplayText))
                pickerEntity.DisplayText = principal.LoginName;

            pickerEntity.Description = principal.LoginName;

            if (!string.IsNullOrEmpty(principal.LoginName))
                pickerEntity.EntityData[UserLimitedGroupSelectionEditor.PeopleInfo.AccountName] = principal.LoginName;

            if (!string.IsNullOrEmpty(principal.JobTitle))
                pickerEntity.EntityData[UserLimitedGroupSelectionEditor.PeopleInfo.JobTitle] = principal.JobTitle;

            if (!string.IsNullOrEmpty(principal.Department))
                pickerEntity.EntityData[UserLimitedGroupSelectionEditor.PeopleInfo.Department] = principal.Department;

            if (!string.IsNullOrEmpty(principal.Email))
                pickerEntity.EntityData[UserLimitedGroupSelectionEditor.PeopleInfo.Email] = principal.Email;

            if (!string.IsNullOrEmpty(principal.SIPAddress))
                pickerEntity.EntityData[UserLimitedGroupSelectionEditor.PeopleInfo.SIPAddress] = principal.SIPAddress;

            if (principal.PrincipalId != -1)
            {
                if (principal.IsSharePointGroup)
                    pickerEntity.EntityData[UserLimitedGroupSelectionEditor.PeopleInfo.SPGroupId] = principal.PrincipalId.ToString(CultureInfo.InvariantCulture);
                else
                    pickerEntity.EntityData[UserLimitedGroupSelectionEditor.PeopleInfo.SPUserId] = principal.PrincipalId.ToString(CultureInfo.InvariantCulture);
            }

            if (!string.IsNullOrEmpty(principal.SIPAddress))
                pickerEntity.EntityData[UserLimitedGroupSelectionEditor.PeopleInfo.SIPAddress] = principal.SIPAddress;

            pickerEntity.EntityData[UserLimitedGroupSelectionEditor.PeopleInfo.PrincipalType] = principal.PrincipalType.ToString();

            if (!string.IsNullOrEmpty(principal.Mobile))
                pickerEntity.EntityData[UserLimitedGroupSelectionEditor.PeopleInfo.MobilePhone] = principal.Mobile;

            return pickerEntity;
        }
    }
}